﻿using System.Data;


namespace Armon.Lib.Algorithm
{
    /// <summary>
    /// 表达式
    /// </summary>
    public static class AExpression
    {
        /// <summary>
        /// 左括号
        /// </summary>
        private static readonly string leftBracket = "(";
        /// <summary>
        /// 右括号
        /// </summary>
        private static readonly string rightBracket = ")";
        /// <summary>
        /// 所有运算符符
        /// </summary>
        private static readonly string[] operators = { "+", "-", "*", "/", ">", "<", ">=", "<=", "=", "!=", "OR", "or", "AND", "and" };
        /// <summary>
        /// 条件运算符
        /// </summary>
        private static readonly string[] conditionalOperators = { "OR", "or", "AND", "and" };
        /// <summary>
        /// 逻辑运算符
        /// </summary>
        private static readonly string[] logicOperators = { ">", "<", ">=", "<=", "=", "!=" };
        /// <summary>
        /// 算术运算符
        /// </summary>
        private static readonly string[] arithmeticOperators = { "+", "-", "*", "/" };

        /// <summary>
        /// 含有必备操作符
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>是/否</returns>
        public static bool HasNecessary(string expression)
        {
            return logicOperators.Any(o => expression.Contains(o));
        }

        /// <summary>
        /// 生成后缀表达式（逆波兰）
        /// </summary>
        /// <param name="expression">表达式数组</param>
        /// <returns>后缀表达式</returns>
        /// <exception cref="InvalidExpressionException"></exception>
        public static List<string> CreatePostfix(List<string> expression)
        {
            var result = new List<string>();
            var stack = new Stack<string>();

            for (var i = 0; i < expression.Count; i++)
            {
                var e = expression[i];
                if (e == leftBracket)
                {
                    stack.Push(e);
                }
                else if (e == rightBracket)
                {
                    while (stack.Count > 0 && stack.Peek() != leftBracket)
                    {
                        result.Add(stack.Pop());
                    }
                    if (stack.Count > 0 && stack.Peek() != leftBracket)
                    {
                        throw new InvalidExpressionException("无效的表达式");
                    }
                    else
                    {
                        stack.Pop();
                    }
                }
                else if (operators.Contains(e))
                {
                    if (i > 0 && operators.Contains(expression[i - 1]))
                    {
                        throw new InvalidExpressionException();
                    }

                    while (stack.Count > 0 && GetPriority(e) <= GetPriority(stack.Peek()))
                    {
                        result.Add(stack.Pop());
                    }
                    stack.Push(e);
                }
                else
                {
                    if (i > 0 && !operators.Contains(expression[i - 1]))
                    {
                        throw new InvalidExpressionException();
                    }

                    if (
                        (decimal.TryParse(e, out _)) &&
                        (e.StartsWith("+") || e.EndsWith("-"))
                    )
                    {
                        throw new InvalidExpressionException();
                    }

                    if (
                        (!decimal.TryParse(e, out _)) &&
                        (!e.StartsWith("[") || !e.EndsWith("]")) &&
                        (!e.StartsWith("'") || !e.EndsWith("'"))
                    )
                    {
                        throw new InvalidExpressionException();
                    }

                    result.Add(e);
                }
            }

            while (stack.Count > 0)
            {
                result.Add(stack.Pop());
            }

            return result;
        }

        /// <summary>
        /// 拆分表达式
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns>数组形式表达式</returns>
        public static List<string> Split(string expression)
        {
            return expression.Split(" ", StringSplitOptions.RemoveEmptyEntries)
                .Select(e => e.Trim())
                .ToList();
        }

        /// <summary>
        /// 根据后缀表达式生成表达式树
        /// </summary>
        /// <param name="postfix">后缀表达式</param>
        /// <returns>表达式树</returns>
        public static Node CreateTree(List<string> postfix)
        {
            var stack = new Stack<Node>();
            foreach (var p in postfix)
            {
                if (operators.Contains(p))
                {
                    var right = stack.Pop();
                    var left = stack.Pop();
                    stack.Push(new Node(p, left, right));
                }
                else
                {
                    stack.Push(new Node(p));
                }

            }
            return stack.Pop();
        }

        /// <summary>
        /// 优先级
        /// </summary>
        /// <param name="o">操作符</param>
        /// <returns>优先级</returns>
        private static int GetPriority(string o)
        {
            return o switch
            {
                "OR" or "AND" or "or" or "and" => 1,
                ">" or "<" or ">=" or "<=" or "=" or "!=" => 2,
                "+" or "-" => 3,
                "*" or "/" => 4,
                _ => 0,
            };
        }

        /// <summary>
        /// 判断条件表达式
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        private static bool IsConditional(Node node)
        {
            if (node is null)
            {
                return false;
            }

            return conditionalOperators.Contains(node.Value);
        }

        /// <summary>
        /// 判断逻辑表达式
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        private static bool IsLogic(Node node)
        {
            if (node is null)
            {
                return false;
            }
            return logicOperators.Contains(node.Value);
        }

        /// <summary>
        /// 判断算术表达式
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        private static bool IsArithmetic(Node node)
        {
            if (node is null)
            {
                return false;
            }
            return arithmeticOperators.Contains(node.Value);
        }

        /// <summary>
        /// 验证表达式树有效
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        /// <exception cref="InvalidExpressionException"></exception>
        public static bool IsValid(Node node)
        {
            if (node is null)
            {
                throw new InvalidExpressionException();
            }

            if (IsConditional(node))
            {
                return IsValidConditional(node);
            }
            if (IsLogic(node))
            {
                return IsValidLogic(node);
            }

            throw new InvalidExpressionException();
        }

        /// <summary>
        /// 判断条件表达式有效
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        /// <exception cref="InvalidExpressionException"></exception>
        private static bool IsValidConditional(Node node)
        {
            if (node.Right.IsLeaf || node.Left.IsLeaf)
            {
                throw new InvalidExpressionException();
            }
            if (!IsLogic(node.Left) && !IsConditional(node.Left))
            {
                throw new InvalidExpressionException();
            }
            if (!IsLogic(node.Right) && !IsConditional(node.Right))
            {
                throw new InvalidExpressionException();
            }

            if (IsConditional(node.Left))
            {
                IsValidConditional(node.Left);
            }
            else
            {
                IsValidLogic(node.Left);
            }

            if (IsConditional(node.Right))
            {
                IsValidConditional(node.Right);
            }
            else
            {
                IsValidLogic(node.Right);
            }

            return true;
        }

        /// <summary>
        /// 判断逻辑表达式有效
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        /// <exception cref="InvalidExpressionException"></exception>
        private static bool IsValidLogic(Node node)
        {
            if (!node.Right.IsLeaf && !IsArithmetic(node.Right))
            {
                throw new InvalidExpressionException();
            }

            if (!node.Left.IsLeaf && !IsArithmetic(node.Left))
            {
                throw new InvalidExpressionException();
            }
            if (IsArithmetic(node.Right))
            {
                IsValidArithmetic(node.Right);
            }
            if (IsArithmetic(node.Left))
            {
                IsValidArithmetic(node.Left);
            }

            return true;
        }

        /// <summary>
        /// 判断算术表达式有效
        /// </summary>
        /// <param name="node">表达式树</param>
        /// <returns>是/否</returns>
        /// <exception cref="InvalidExpressionException"></exception>
        private static bool IsValidArithmetic(Node node)
        {
            if (node.IsLeaf)
            {
                return true;
            }

            if (node.Right is null || node.Left is null)
            {
                throw new InvalidExpressionException();
            }

            if (IsArithmetic(node.Right))
            {
                IsValidArithmetic(node.Right);
            }
            if (IsArithmetic(node.Left))
            {
                IsValidArithmetic(node.Left);
            }

            return true;
        }

        /// <summary>
        /// 条件运算
        /// </summary>
        /// <param name="o">运算符</param>
        /// <param name="a">操作数</param>
        /// <param name="b">操作数</param>
        /// <returns>结果</returns>
        private static bool OperateConditional(string o, bool a, bool b)
        {
            o = o.ToLower();

            return o switch
            {
                "or" => a || b,
                "and" => a && b,
                _ => false
            };
        }

        /// <summary>
        /// 逻辑运算
        /// </summary>
        /// <param name="o">运算符</param>
        /// <param name="a">操作数</param>
        /// <param name="b">操作数</param>
        /// <returns>结果</returns>
        /// <exception cref="InvalidExpressionException">无效表达式</exception>
        private static bool OperateLogic(string o, object a, object b)
        {
            var a1 = a.ToString();
            var b1 = b.ToString();

            var isAOk = decimal.TryParse(a1, out decimal a2);
            var isBOk = decimal.TryParse(b1, out decimal b2);
            if ((!isAOk || !isBOk) && (o != "=" && o != "!="))
            {
                throw new InvalidExpressionException();
            }

            if ((!isAOk && isBOk) || ((isAOk && !isBOk)) && (o == "=" || o == "!="))
            {
                throw new InvalidExpressionException();
            }

            return o switch
            {
                ">" => a2 > b2,
                "<" => a2 < b2,
                ">=" => a2 >= b2,
                "<=" => a2 <= b2,
                "=" => a2 == b2,
                "!=" => a2 != b2,
                _ => false
            };
        }

        /// <summary>
        /// 算术运算
        /// </summary>
        /// <param name="o">运算符</param>
        /// <param name="a">操作数</param>
        /// <param name="b">操作数</param>
        /// <returns>结果</returns>
        /// <exception cref="InvalidExpressionException">无效表达式</exception>
        private static decimal OperateArithmetic(string o, object a, object b)
        {
            var a1 = a.ToString();
            var b1 = b.ToString();

            var isAOk = decimal.TryParse(a1, out decimal a2);
            var isBOk = decimal.TryParse(b1, out decimal b2);
            if (!isAOk || !isBOk)
            {
                throw new InvalidExpressionException();
            }

            return o switch
            {
                "+" => a2 + b2,
                "-" => a2 - b2,
                "*" => a2 * b2,
                "/" => a2 / b2,
                _ => 0
            };
        }

        /// <summary>
        /// 计算逻辑表达式
        /// </summary>
        /// <param name="node">后缀表达式树</param>
        /// <returns>结果</returns>
        private static bool CalculateLogic(Node node)
        {
            object left = node.Left.Value;
            if (IsArithmetic(node.Left))
            {
                left = CalculateArithmetic(node.Left);
            }

            object right = node.Right.Value;
            if (IsArithmetic(node.Right))
            {
                right = CalculateArithmetic(node.Right);
            }

            return OperateLogic(node.Value, left, right);
        }

        /// <summary>
        /// 计算算术表达式
        /// </summary>
        /// <param name="node">后缀表达式树</param>
        /// <returns>结果</returns>
        private static decimal CalculateArithmetic(Node node)
        {
            object left = node.Left.Value;
            if (IsArithmetic(node.Left))
            {
                left = CalculateArithmetic(node.Left);
            }

            object right = node.Right.Value;
            if (IsArithmetic(node.Right))
            {
                right = CalculateArithmetic(node.Right);
            }

            return OperateArithmetic(node.Value, left, right);
        }

        /// <summary>
        /// 计算表达式
        /// </summary>
        /// <param name="node">后缀表达式树</param>
        /// <returns>结果</returns>
        /// <exception cref="InvalidExpressionException">无效表达式</exception>
        public static bool Calculate(Node node)
        {
            if (node is null)
            {
                throw new InvalidExpressionException();
            }

            if (!IsConditional(node))
            {
                return CalculateLogic(node);
            }

            var left = false;
            if (IsConditional(node.Left))
            {
                left = Calculate(node.Left);
            }
            else
            {
                left = CalculateLogic(node.Left);
            }

            var right = false;
            if (IsConditional(node.Right))
            {
                right = Calculate(node.Right);
            }
            else
            {
                right = CalculateLogic(node.Right);
            }

            return OperateConditional(node.Value, left, right);
        }
    }
}
